home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / msysjour / vol04 / 02a / mdi / mdi1.c < prev    next >
C/C++ Source or Header  |  1988-12-06  |  20KB  |  658 lines

  1. /*
  2.  * MDI1.C - Application Interface
  3.  *
  4.  * LANGUAGE      : Microsoft C5.1
  5.  * MODEL         : medium
  6.  * ENVIRONMENT   : Microsoft Windows 2.1 SDK
  7.  * STATUS        : operational
  8.  *
  9.  * This module contains all the MDI code to handle the programmatic
  10.  * interface.  This includes window creation, default message handling,
  11.  * and message loop support code.  The MDI desktop window and the
  12.  * document windows have separate creation and message handling
  13.  * routines, while the message loop support is window independant.
  14.  *
  15.  * Developed by:
  16.  *   Geoffrey Nicholls
  17.  *   Kevin P. Welch
  18.  *
  19.  * (C) Copyright 1988
  20.  * Eikon Systems, Inc.
  21.  * 989 E. Hillsdale Blvd, Suite 260
  22.  * Foster City  CA  94404
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <windows.h>
  28.  
  29. #include "mdi.h"
  30.  
  31. /* External variables */
  32. extern int        iCurrentPopup;          /* What menu is up */
  33. extern int        iNextPopup;             /* What menu is next */
  34.  
  35. /* */
  36.  
  37. /*
  38.  * MdiMainCreateWindow( ... ) : HWND;
  39.  *
  40.  *    szClassName    Class name of MDI desktop
  41.  *    szTitleName    Caption for MDI desktop
  42.  *    lStyle         Style of MDI desktop
  43.  *    wLeft          Left position of window
  44.  *    wTop           Top position of window
  45.  *    wWidth         Width of window
  46.  *    wHeight        Height of window
  47.  *    hwndParent     Parent of MDI desktop
  48.  *    hmenuMain      Handle to menu
  49.  *    hInst          Current instance handle
  50.  *    lpCreateParam  Pointer to creation parameters
  51.  *
  52.  * Create the MDI desktop window.  The parameters exactly match the
  53.  * Windows call CreateWindow().  The MDI code keeps track of desktop
  54.  * information in property lists, such as handles to menus,
  55.  * accelerators, and bitmaps as well as counts of document windows.
  56.  *
  57.  */
  58.  
  59. HWND MdiMainCreateWindow(
  60.    LPSTR       szClassName,
  61.    LPSTR       szTitleName,
  62.    DWORD       lStyle,
  63.    int         wLeft,
  64.    int         wTop,
  65.    int         wWidth,
  66.    int         wHeight,
  67.    HWND        hwndParent,
  68.    HMENU       hmenuMain,
  69.    HANDLE      hInst,
  70.    LPSTR       lpCreateParam )
  71. {
  72.    HWND        hwndMain;         /* Handle of MDI desktop */
  73.  
  74.    hwndMain = CreateWindow( szClassName,
  75.       szTitleName,
  76.       lStyle,
  77.       wLeft, wTop, wWidth, wHeight,
  78.       hwndParent,
  79.       hmenuMain,
  80.       hInst,
  81.       lpCreateParam );
  82.  
  83.    /* Success? */
  84.    if ( hwndMain )
  85.    {
  86.       /* Message hook for tracking keyboard interface to menu */
  87.       MdiSetMenuKeyHook( hInst );
  88.  
  89.       /* Make sure variables are initialized */
  90.       SetProp( hwndMain, PROP_ACTIVE, NULL );
  91.       SetProp( hwndMain, PROP_COUNT, 0 );
  92.       SetProp( hwndMain, PROP_HIDDEN, 0 );
  93.       SetProp( hwndMain, PROP_ZOOM, FALSE );
  94.       SetProp( hwndMain, PROP_MAINMENU, GetMenu( hwndMain ) );
  95.       SetProp( hwndMain, PROP_WINDOWMENU, LoadMenu(hInst, "MdiMenu") );
  96.       SetProp( hwndMain,
  97.          PROP_CTRLACCEL,
  98.          LoadAccelerators( hInst, "MdiChildAccel" ) );
  99.       SetProp( hwndMain,
  100.          PROP_SYSMENU,
  101.          MdiCreateChildSysBitmap( hwndMain ) );
  102.       SetProp( hwndMain, PROP_TITLE, AddAtom( szTitleName ) );
  103.  
  104.       /* Attach window menu to main menu */
  105.       MdiWindowMenu( hwndMain, GetMenu( hwndMain ), TRUE);
  106.    }
  107.    return hwndMain;
  108. }
  109.  
  110. /* */
  111.  
  112. /*
  113.  * MdiMainDefWindowProc( hwndMain, message, wParam, lParam ) : long;
  114.  *
  115.  *    hwndMain       Handle to MDI desktop
  116.  *    message        Current message
  117.  *    wParam         Word parameter to message
  118.  *    lParam         Long parameter to message
  119.  *
  120.  * Handle the MDI desktop messages.  Messages reach here only after
  121.  * the application MDI desktop window procedure has processed those
  122.  * that it wants.  Major occurances that are recognized in this
  123.  * function include:  parent window activation & deactivation, WINDOW
  124.  * menu messages (esp for switching between children), record keeping
  125.  * of which menu is currently poped up (if any), and sizing of
  126.  * document windows which are maximized.
  127.  *
  128.  */
  129.  
  130. long MdiMainDefWindowProc(
  131.    HWND        hwndMain,
  132.    unsigned    message,
  133.    WORD        wParam,
  134.    LONG        lParam )
  135. {
  136.    FARPROC     lpProc;           /* Procedure instance for dialogs */
  137.    HANDLE      hInst;            /* Current instance handle */
  138.    HWND        hwndActive;       /* Currently active document window */
  139.    HWND        hwndChosen;       /* Newly chosen document window */
  140.    HWND        hwndIter;         /* Iterating document windows */
  141.    LONG        lStyle;           /* Window style */
  142.    RECT        rcClient;         /* Client area of MDI desktop */
  143.  
  144.    hwndActive = GetProp( hwndMain, PROP_ACTIVE );
  145.    switch ( message )
  146.    {
  147.    case WM_ACTIVATE:
  148.       /* MDI child reflects the activation status of the parent */
  149.       if ( hwndActive )
  150.       {
  151.          switch( wParam )
  152.          {
  153.          case 0:
  154.             /* Deactivating */
  155.             MdiDeactivateChild( hwndActive );
  156.             break;
  157.  
  158.          case 1:
  159.          case 2:
  160.             /* Activating */
  161.             MdiActivateChild( hwndActive, FALSE );
  162.             break;
  163.          }
  164.       }
  165.       break;
  166.  
  167.    case WM_COMMAND:
  168.       hInst = GetWindowWord( hwndMain, GWW_HINSTANCE );
  169.       switch ( wParam )
  170.       {
  171.       case IDM_UNHIDE:
  172.          /* Unhide dialog box */
  173.          lpProc = MakeProcInstance( MdiDlgUnhide, hInst );
  174.          hwndChosen = DialogBox( hInst, "MdiUnhide", hwndMain, lpProc);
  175.          if ( hwndChosen )
  176.          {
  177.             /* MDI child being unhidden */
  178.             MdiUnhideChild( hwndChosen );
  179.          }
  180.          FreeProcInstance( lpProc );
  181.          break;
  182.  
  183.       default:
  184.          /* Is this a WINDOW menu message to select an MDI child */
  185.          if ( wParam > IDM_FIRSTWIN
  186.             && wParam <= IDM_FIRSTWIN + GetProp( hwndMain, PROP_COUNT))
  187.          {
  188.             /* Iterate all the children of the mdi parent */
  189.             for ( hwndIter = GetTopWindow( hwndMain );
  190.                hwndIter != NULL;
  191.                hwndIter = GetWindow( hwndIter, GW_HWNDNEXT ) )
  192.             {
  193.                /* Ignore self & non-mdi children */
  194.                if ( hwndIter == hwndActive
  195.                   || !GetProp( hwndIter, PROP_ISMDI ) )
  196.                {
  197.                   continue;
  198.                }
  199.  
  200.                /* Is this the window? */
  201.                if ( wParam == GetProp( hwndIter, PROP_MENUID ) )
  202.                {
  203.                   /* Make a new MDI child the current one */
  204.                   if ( GetProp( hwndMain, PROP_ZOOM ) )
  205.                   {
  206.                      MdiSwitchZoom( hwndIter, hwndActive );
  207.                   }
  208.                   MdiActivateChild( hwndIter, FALSE );
  209.                   break;
  210.                }
  211.             }
  212.          }
  213.          else
  214.          {
  215.             if ( hwndActive )
  216.             {
  217.                /* MDI child gets all other WM_COMMAND messages */
  218.                return SendMessage(hwndActive, message, wParam, lParam);
  219.             }
  220.          }
  221.          break;
  222.       }
  223.       break;
  224.  
  225.    case WM_DESTROY:
  226.       /* Let MDI clean up */
  227.       DeleteObject( GetProp( hwndMain, PROP_SYSMENU ) );
  228.       DeleteAtom( GetProp( hwndMain, PROP_TITLE ) );
  229.       MdiFreeMenuKeyHook( );
  230.       break;
  231.  
  232.    case WM_INITMENU:
  233.       /* Anything to hide? */
  234.       EnableMenuItem( ( HMENU ) wParam,
  235.          IDM_HIDE,
  236.          hwndActive ? MF_ENABLED : MF_GRAYED );
  237.  
  238.       /* Any hidden windows?  Gray UNHIDE appropriately */
  239.       EnableMenuItem( ( HMENU ) wParam,
  240.          IDM_UNHIDE,
  241.          GetProp( hwndMain, PROP_HIDDEN ) ? MF_ENABLED : MF_GRAYED );
  242.  
  243.       /* Maybe the MDI child wants to do something too */
  244.       if ( hwndActive )
  245.       {
  246.          SendMessage( hwndActive, message, wParam, lParam );
  247.       }
  248.       break;
  249.  
  250.    case WM_INITMENUPOPUP:
  251.       /* Keep track of which menu is popped up so that if we hit a left
  252.       ** or right arrow, we know which the next menu to popup is.
  253.       */
  254.       if ( HIWORD( lParam ) )
  255.       {
  256.          iCurrentPopup = POP_MAINSYS;
  257.       }
  258.       else
  259.       {
  260.          iCurrentPopup = LOWORD( lParam );
  261.          if ( GetProp( hwndMain, PROP_ZOOM ) )
  262.             iCurrentPopup--;
  263.       }
  264.       if ( hwndActive )
  265.       {
  266.          /* Let the MDI child do something with this too */
  267.          SendMessage( hwndActive, message, wParam, lParam );
  268.       }
  269.       break;
  270.  
  271.    case WM_MENUCHAR:
  272.       if ( wParam == '-' )
  273.       {
  274.          /* Bring up active MDI child's system menu */
  275.          if ( ( LOWORD( lParam ) & MF_POPUP ) == 0 && hwndActive )
  276.          {
  277.             /* Is the MDI child zoomed? */
  278.             if ( GetProp( hwndMain, PROP_ZOOM ) )
  279.             {
  280.                /* MDI child system menu is on the main menu bar */
  281.                return MAKELONG( 0, MC_SELECT );
  282.             }
  283.  
  284.             iNextPopup = POP_CHILDSYS;
  285.             /* This result will cause no menu to hilite, but because
  286.             ** iNextPopup is set, the call right after the message
  287.             ** processing loop will hilite the child system menu
  288.             */
  289.             return MAKELONG( 0, MC_ABORT );
  290.          }
  291.          break;
  292.       }
  293.       break;
  294.  
  295.    case WM_SETFOCUS:
  296.       /* Make the MDI child reflect the focus status of the MDI main */
  297.       if ( hwndActive )
  298.       {
  299.          SetFocus( hwndActive );
  300.       }
  301.       break;
  302.  
  303.    case WM_SIZE:
  304.       if ( wParam != SIZEICONIC )
  305.       {
  306.          /* Resize MDI child if zoomed */
  307.          if ( GetProp( hwndMain, PROP_ZOOM ) )
  308.          {
  309.             GetClientRect( hwndMain, &rcClient );
  310.             lStyle = GetWindowLong( hwndActive, GWL_STYLE );
  311.             AdjustWindowRect( &rcClient, lStyle, FALSE );
  312.             MoveWindow( hwndActive,
  313.                rcClient.left,
  314.                rcClient.top,
  315.                rcClient.right - rcClient.left,
  316.                rcClient.bottom - rcClient.top,
  317.                TRUE );
  318.          }
  319.       }
  320.       break;
  321.    }
  322.    return DefWindowProc( hwndMain, message, wParam, lParam );
  323. }
  324.  
  325. /* */
  326.  
  327. /*
  328.  * MdiChildCreateWindow( ... ) : HWND;
  329.  *
  330.  *    szClassName    Class name of document
  331.  *    szTitleName    Caption for document
  332.  *    lStyle         Style of document
  333.  *    wLeft          Left position of window
  334.  *    wTop           Top position of window
  335.  *    wWidth         Width of window
  336.  *    wHeight        Height of window
  337.  *    hwndMain       MDI desktop
  338.  *    hmenuChild     Handle to document menu
  339.  *    hInst          Current instance handle
  340.  *    lpCreateParam  Pointer to creation parameters
  341.  *
  342.  * Create an MDI document window.  The parameters exactly match the
  343.  * Windows call CreateWindow() except that the hmenuChild message
  344.  * must be a valid menu handle, whereas the CreateWindow() call expects
  345.  * a child id.  The MDI code keeps track of document information in
  346.  * property lists, such as handles to menus and accelerators, as well
  347.  * as whether this child of the MDI desktop is an MDI document.
  348.  *
  349.  */
  350.  
  351. HWND MdiChildCreateWindow(
  352.    LPSTR       szClassName,
  353.    LPSTR       szTitleName,
  354.    DWORD       lStyle,
  355.    int         wLeft,
  356.    int         wTop,
  357.    int         wWidth,
  358.    int         wHeight,
  359.    HWND        hwndMain,
  360.    HMENU       hmenuChild,
  361.    HANDLE      hInst,
  362.    LPSTR       lpCreateParam )
  363. {
  364.    char        szTitle[128];     /* Title for document */
  365.    char        szCompose[128];   /* Used to compose title */
  366.    int         iCount;           /* Child window ID */
  367.    int         wLeftAct = wLeft;       /* Left position of window */
  368.    int         wTopAct = wTop;         /* Top position of window */
  369.    int         wWidthAct = wWidth;     /* Width of window */
  370.    int         wHeightAct = wHeight;   /* Height of window */
  371.    HWND        hwndActive;       /* Currently active document window */
  372.    HWND        hwndChild;        /* Handle of document window */
  373.    RECT        rcClient;         /* Client area of MDI desktop */
  374.  
  375.    /* Calculate size & position */
  376.    iCount = GetProp( hwndMain, PROP_COUNT );
  377.    if ( wLeftAct == CW_USEDEFAULT )
  378.       wLeftAct = 10 + 15 * iCount;
  379.    if ( wTopAct == CW_USEDEFAULT )
  380.       wTopAct = 10 + 15 * iCount;
  381.    if ( wWidthAct == CW_USEDEFAULT )
  382.       wWidthAct = 200;
  383.    if ( wHeightAct == CW_USEDEFAULT )
  384.       wHeightAct = 75;
  385.  
  386.    /* Ensure that it falls within client area */
  387.    GetClientRect( hwndMain, &rcClient );
  388.    if ( wLeft == CW_USEDEFAULT )
  389.       while ( wLeftAct > rcClient.right )
  390.          wLeftAct -= rcClient.right;
  391.    if ( wTop == CW_USEDEFAULT )
  392.       while ( wTopAct > rcClient.bottom )
  393.          wTopAct -= rcClient.bottom;
  394.  
  395.    /* Create it */
  396.    hwndChild = CreateWindow( szClassName,
  397.       szTitleName,
  398.       lStyle,
  399.       wLeftAct, wTopAct, wWidthAct, wHeightAct,
  400.       hwndMain,
  401.       ( HMENU ) iCount,
  402.       hInst,
  403.       lpCreateParam );
  404.  
  405.    /* Success? */
  406.    if ( hwndChild )
  407.    {
  408.       /* New child */
  409.       SetProp( hwndMain, PROP_COUNT, ++iCount );
  410.  
  411.       /* Keep important info */
  412.       SetProp( hwndChild, PROP_CHILDMENU, hmenuChild );
  413.       SetProp( hwndChild, PROP_ACCEL, 0 );
  414.       SetProp( hwndChild, PROP_MENUID, IDM_FIRSTWIN + iCount );
  415.       SetProp( hwndChild, PROP_ISMDI, TRUE );
  416.  
  417.       /* Reflect change in WINDOW menu */
  418.       MdiAppendWindowToMenu( hwndChild );
  419.  
  420.       /* Let's activate this MDI child */
  421.       hwndActive = GetProp( hwndMain, PROP_ACTIVE );
  422.       if ( GetProp( hwndMain, PROP_ZOOM ) )
  423.       {
  424.          MdiSwitchZoom( hwndChild, hwndActive );
  425.       }
  426.       MdiActivateChild( hwndChild, FALSE );
  427.  
  428.       /* Show menu bar changes now */
  429.       DrawMenuBar( hwndMain );
  430.    }
  431.    return hwndChild;
  432. }
  433.  
  434. /* */
  435.  
  436. /*
  437.  * MdiChildDefWindowProc( hwndChild, message, wParam, lParam ) : long;
  438.  *
  439.  *    hwndChild      Handle to document
  440.  *    message        Current message
  441.  *    wParam         Word parameter to message
  442.  *    lParam         Long parameter to message
  443.  *
  444.  * Handle MDI document messages.  Messages reach here only after the
  445.  * application document window proedure has processed those that it
  446.  * wants.  Major occurances that are recognized in this function
  447.  * include:  child system menu choices, window creation, window
  448.  * activation, window destruction, and translating <alt>- into
  449.  * selecting the child system menu.
  450.  *
  451.  */
  452.  
  453. long MdiChildDefWindowProc(
  454.    HWND        hwndChild,
  455.    unsigned    message,
  456.    WORD        wParam,
  457.    LONG        lParam )
  458. {
  459.    HWND        hwndMain;         /* Handle to MDI desktop */
  460.    PAINTSTRUCT Paint;            /* Paint structure */
  461.  
  462.    hwndMain = GetParent( hwndChild );
  463.    switch ( message )
  464.    {
  465.    case WM_CLOSE:
  466.       /* We're going away */
  467.       MdiDestroyChildWindow( hwndChild );
  468.       break;
  469.  
  470.    case WM_COMMAND:
  471.       switch( wParam )
  472.       {
  473.       case IDM_HIDE:
  474.          /* MDI child being hidden */
  475.          MdiHideChild( hwndChild );
  476.          break;
  477.  
  478.       case IDM_RESTORE:
  479.          SendMessage( hwndChild, WM_SYSCOMMAND, SC_RESTORE, lParam );
  480.          break;
  481.  
  482.       case IDM_MOVE:
  483.          SendMessage( hwndChild, WM_SYSCOMMAND, SC_MOVE, lParam );
  484.          break;
  485.  
  486.       case IDM_SIZE:
  487.          SendMessage( hwndChild, WM_SYSCOMMAND, SC_SIZE, lParam );
  488.          break;
  489.  
  490.       case IDM_MAXIMIZE:
  491.          SendMessage( hwndChild, WM_SYSCOMMAND, SC_MAXIMIZE, lParam );
  492.          break;
  493.  
  494.       case IDM_PREVWINDOW:
  495.          /* This function is achieved only through the keyboard */
  496.          SendMessage( hwndChild, WM_SYSCOMMAND, SC_PREVWINDOW, lParam);
  497.          break;
  498.  
  499.       case IDM_NEXTWINDOW:
  500.          /* This function is achieved only through the keyboard */
  501.          SendMessage( hwndChild, WM_SYSCOMMAND, SC_NEXTWINDOW, lParam);
  502.          break;
  503.       }
  504.       break;
  505.  
  506.    case WM_INITMENU:
  507.       MdiInitSystemMenu( hwndChild );
  508.       break;
  509.  
  510.    case WM_MENUCHAR:
  511.       /* Was the <alt>- key hit when no popup currently popped up? */
  512.       if ( ( LOWORD( lParam ) & MF_POPUP ) == 0 )
  513.       {
  514.          if ( wParam == '-' )
  515.          {
  516.             /* Let Alt-Minus mean activate our system menu */
  517.             return MAKELONG( 0, MC_SELECT );
  518.          }
  519.          else
  520.          {
  521.             /* Another <alt> key stroke, let the parent handle it */
  522.             SendMessage( hwndMain,
  523.                WM_SYSCOMMAND,
  524.                SC_KEYMENU,
  525.                ( DWORD ) wParam );
  526.             return MAKELONG( 0, MC_ABORT );
  527.          }
  528.       }
  529.       break;
  530.  
  531.    case WM_MENUSELECT:
  532.       iCurrentPopup = POP_CHILDSYS;
  533.       break;
  534.  
  535.    case WM_MOUSEACTIVATE:
  536.       MdiActivateChild( hwndChild, FALSE );
  537.       break;
  538.  
  539.    case WM_SYSCOMMAND:
  540.       switch( wParam & 0xFFF0 )
  541.       {
  542.       case SC_KEYMENU:
  543.          if ( GetProp( hwndMain, PROP_ZOOM ) || LOWORD(lParam) != '-' )
  544.          {
  545.             /* Pass any other Alt-Key messages to the parent */
  546.             return SendMessage(hwndMain,WM_SYSCOMMAND, wParam, lParam);
  547.          }
  548.          break;
  549.  
  550.       case SC_MAXIMIZE:
  551.          if ( GetProp( hwndMain, PROP_ZOOM ) )
  552.          {
  553.             SetProp( hwndMain, PROP_ZOOM, FALSE );
  554.             MdiRestoreChild( hwndChild, TRUE );
  555.          }
  556.          else
  557.          {
  558.             SetProp( hwndMain, PROP_ZOOM, TRUE );
  559.             MdiZoomChild( hwndChild );
  560.          }
  561.          return 0L;
  562.  
  563.       case SC_RESTORE:
  564.          if ( GetProp( hwndMain, PROP_ZOOM ) )
  565.          {
  566.             SetProp( hwndMain, PROP_ZOOM, FALSE );
  567.             MdiRestoreChild( hwndChild, TRUE );
  568.          }
  569.          return 0L;
  570.  
  571.       case SC_NEXTWINDOW:
  572.          /* This function is achieved only through the keyboard */
  573.          MdiActivateNextChild( hwndChild );
  574.          return 0L;
  575.  
  576.       case SC_PREVWINDOW:
  577.          /* This function is achieved only through the keyboard */
  578.          MdiActivatePrevChild( hwndChild );
  579.          return 0L;
  580.       }
  581.       break;
  582.    }
  583.    return DefWindowProc( hwndChild, message, wParam, lParam );
  584. }
  585.  
  586. /* */
  587.  
  588. /*
  589.  * MdiGetMessage( hwndMain, lpMsg, hWnd, wMin, wMax ) : BOOL;
  590.  *
  591.  *    hwndMain       Handle to MDI desktop
  592.  *    lpMsg          Message structure to receive message
  593.  *    hWnd           Are messages for a specific window only?
  594.  *    wMin           Is there a minimum message number?
  595.  *    wMax           Is there a maximum message number?
  596.  *
  597.  * Get a normal windows message only after checking for keyboard
  598.  * access to the menus.
  599.  *
  600.  */
  601.  
  602. BOOL MdiGetMessage(
  603.    HWND        hwndMain,
  604.    LPMSG       lpMsg,
  605.    HWND        hWnd,
  606.    WORD        wMin,
  607.    WORD        wMax )
  608. {
  609.    /* Process keyboard interface to menu */
  610.    MdiMenuMessageLoopUpdate( hwndMain );
  611.  
  612.    /* Now go get the next message */
  613.    return GetMessage( lpMsg, hWnd, wMin, wMax );
  614. }
  615.  
  616. /* */
  617.  
  618. /*
  619.  * MdiTranslateAccelerators( hwndMain, lpMsg ) : int
  620.  *
  621.  *    hwndMain       Handle to MDI desktop
  622.  *    lpMsg          Message structure containing message
  623.  *
  624.  * Translate this message via one of two accelerator tables:
  625.  *  1) The document's system menu (i.e. <ctrl><F4>)
  626.  *  2) The document's own accelerator table.  This table
  627.  *     is set with the MdiSetAccelerator() call.
  628.  *
  629.  */
  630.  
  631. int MdiTranslateAccelerators(
  632.    HWND        hwndMain,
  633.    LPMSG       lpMsg )
  634. {
  635.    int         iResult = 0;      /* Result of last translation */
  636.    HANDLE      hAccel;           /* Each of the two accel tables */
  637.    HWND        hwndChild;        /* Handle to document */
  638.  
  639.    /* Is there a document on the MDI desktop? */
  640.    hwndChild = GetProp( hwndMain, PROP_ACTIVE );
  641.    if ( hwndChild )
  642.    {
  643.       /* Check for system accelerators */
  644.       hAccel = GetProp( hwndMain, PROP_CTRLACCEL );
  645.       iResult = TranslateAccelerator( hwndMain, hAccel, lpMsg );
  646.       if ( !iResult )
  647.       {
  648.          /* Check for document accelerators */
  649.          hAccel = GetProp( hwndChild, PROP_ACCEL );
  650.          if ( hAccel )
  651.          {
  652.             iResult = TranslateAccelerator( hwndMain, hAccel, lpMsg );
  653.          }
  654.       }
  655.    }
  656.    return iResult;
  657. }
  658.